/*
 * ConnectionManager.cpp
 *
 *  Created on: Nov 21, 2014
 *      Author: toti
 */

#include <Connectivity/ConnectionManager.hpp>

ConnectionManager::ConnectionManager() {

	ndc = NetworkDataContainer::instance();

	localClientTcpServer = 0;
	localServerTcpServer = 0;

	epoll = new EPoll(32);

}

void ConnectionManager::initParentServer() {

	TCPClient parentServerClient(false);
	TCPConnection *parentServerTcpConnection;
	LocalServer *localServer;
	ServerMessagePackage *serverMessagePackage;

	parentServerTcpConnection = parentServerClient.openConnection(
			Config::instance()->getParentServerPort(),
			Config::instance()->getAddress());

	localServer = new LocalServer(parentServerTcpConnection);

	ndc->parentServer = localServer;

	epoll->addFd(parentServerTcpConnection->getSock(), localServer);

	serverMessagePackage = new ServerMessagePackage();
	serverMessagePackage->setMessageType(ServerMessagePackage::TYPE_SERVER_REGISTRATION);
	serverMessagePackage->setSender(Config::instance()->getServerName());
	serverMessagePackage->generateMessageString();

	localServer->pushOutputPackage((MessagePackage*)serverMessagePackage);

}

void ConnectionManager::initChildServer() {

	localServerTcpServer = new TCPServer(
			Config::instance()->getChildServerPort(), false);
	localClientTcpServer = new TCPServer(
			Config::instance()->getChildClientPort(), false);

	epoll->addFd(localServerTcpServer->getSock(), localServerTcpServer);
	epoll->addFd(localClientTcpServer->getSock(), localClientTcpServer);

}

void ConnectionManager::handleInput() {

	int n = epoll->wait();

	for (int i = 0; i < n; i++) {

		struct epoll_event *event = epoll->getEventBuffer(i);

		if ((event->events & EPOLLERR) || (event->events & EPOLLHUP)
				|| (event->events & EPOLLRDHUP)) {

			handleExistingLocalNodeError((LocalNode*)event->data.ptr);

		} else if (event->events & EPOLLIN) {

			if (event->data.ptr == localClientTcpServer) {

				handleNewLocalClientConnections((TCPServer*)localClientTcpServer);

			} else if (event->data.ptr == localServerTcpServer) {

				handleNewLocalServerConnections((TCPServer*)localServerTcpServer);

			} else {

				handleExistingLocalNodeConnection((LocalNode*)event->data.ptr);

			}

		}

	}

}

void ConnectionManager::handleOutput() {

	if (ndc->parentServer) {
		ndc->parentServer->handleOutputData();
	}

	handleLocalNodeOutputData(ndc->localClientList);
	handleLocalNodeOutputData(ndc->localServerList);

}



void ConnectionManager::handleExistingLocalNodeError(LocalNode *localNode){

	epoll->remFd(localNode->getTcpConnection()->getSock());

	ndc->localServerList->remove(localNode);
	delete(localNode);

}


void ConnectionManager::handleNewLocalClientConnections(TCPServer *tcpServer) {

	TCPConnection *tcpConnection = localClientTcpServer->waitForConnection();
	LocalClient *localClient = new LocalClient(tcpConnection);

	ndc->localClientList->push_back(localClient);
	epoll->addFd(tcpConnection->getSock(), localClient);

	localClient->initDefaultNick();

	std::cout << "New client connection!" << std::endl;

}

void ConnectionManager::handleNewLocalServerConnections(TCPServer *tcpServer) {

	TCPConnection *tcpConnection = localServerTcpServer->waitForConnection();
	LocalServer *localServer = new LocalServer(tcpConnection);

	epoll->addFd(tcpConnection->getSock(), localServer);
	ndc->localServerList->push_back(localServer);

	localServer->deployServerList();

	std::cout << "New server connection!" << std::endl;

}

void ConnectionManager::handleExistingLocalNodeConnection(LocalNode *localNode){


	if(localNode->handleInputData()){
		localNode->processData();
	}else{
		handleExistingLocalNodeError(localNode);
	}

}

void ConnectionManager::handleLocalNodeOutputData(
		std::list<LocalNode*> *localNodeList) {

	for (std::list<LocalNode*>::iterator it = localNodeList->begin();
			it != localNodeList->end(); ++it) {

		(*it)->handleOutputData();

	}
}


